很多候选人还在背:
但现在中高级岗位更关心:
"use cache")很多人回答:
"因为 Server Component 运行在服务器,所以可以直接 await fetch。"
这句话没有错,但太浅了。Senior 面试通常会继续追问:
为什么不需要 useEffect?useEffect 到底解决什么问题?
下面我按照面试的思路来讲。
React 最初(CSR):
xxxxxxxxxxBrowser↓Render↓Commit↓useEffect↓fetch()↓setState()↓Render↓页面显示数据例如:
xxxxxxxxxx"use client";function UserList() { const [users, setUsers] = useState([]); useEffect(() => { fetch("/api/users") .then(res => res.json()) .then(setUsers); }, []); return <Table users={users} />;}第一次页面是什么?
xxxxxxxxxx[]然后:
xxxxxxxxxxLoading...↓请求完成↓重新 Render↓显示数据
所以 useEffect 的作用其实是:
在组件已经渲染完成之后,再去执行副作用(例如请求数据)。
因为 React 有规定:
Render 必须是纯函数(Pure Function)。
也就是说:
Render 阶段不能:
例如:
xxxxxxxxxxfunction App() { const users = fetch("/api/users"); // ❌ React 不允许 return }为什么?
因为 Render 可能:
xxxxxxxxxxRender↓暂停↓重新开始↓重复执行
如果 Render 可以发请求:
xxxxxxxxxxRender↓fetch()↓Render Again↓fetch()↓Render Again↓fetch()
可能发送很多重复请求。
所以 React 才规定:
Render 必须纯。
数据请求只能放:
xxxxxxxxxxCommit↓useEffect
这是 App Router 最大的变化。
Server Component:
xxxxxxxxxxexport default async function Page() { const users = await getUsers(); return <Table users={users} />;}很多人看到:
xxxxxxxxxxawait getUsers();就觉得:
不是副作用吗?
其实:
Server Component 根本不是 React 浏览器里的 Render。
它是在 Node.js(或 Edge Runtime)执行:
xxxxxxxxxxNode.js↓await database↓await fetch↓生成 HTML↓发送 HTML 给浏览器
整个过程:
xxxxxxxxxxServer↓fetch()↓得到数据↓Render HTML↓Send HTML
浏览器收到时:
xxxxxxxxxx<table> ...</table>数据已经存在。
根本没有:
xxxxxxxxxxLoading...↓再请求
因为:
Server Component 在生成 JSX 之前,数据已经拿到了。
流程:
xxxxxxxxxxServer↓await fetch()↓得到数据↓生成 JSX↓HTML↓浏览器
React 根本不需要:
xxxxxxxxxxCommit↓useEffect↓fetch↓setState
这一整套流程。
很多人这里容易困惑。
React 一直强调:
xxxxxxxxxxRender 必须纯
为什么:
xxxxxxxxxxexport default async function Page() { const users = await getUsers();}却可以?
原因就在于:
React 对 Server Component 的 Render 和 Client Component 的 Render 是两种不同的执行环境。
Client:
xxxxxxxxxxRender↓必须同步↓不能 await
Server:
xxxxxxxxxxNode.js↓允许 async↓等待 Promise↓继续 Render
服务器没有:
所以:
等待数据库:
xxxxxxxxxx20ms
没有关系。
普通 React:
xxxxxxxxxxfunction App() {}不能:
xxxxxxxxxxasync function App() {}React 会报错。
但是:
Server Component:
xxxxxxxxxxexport default async function Page() {}是:
Next.js + React Server Component 扩展支持的能力。
React 官方就是为了服务器渲染专门设计的。
例如:
xxxxxxxxxx"use client";export default async function Page() { const users = await getUsers();}不允许。
为什么?
浏览器需要:
xxxxxxxxxxRender↓立即返回 JSX
而:
xxxxxxxxxxawait↓暂停 Render
React Client Render 是同步计算 Virtual DOM 的过程。
不能:
xxxxxxxxxxRender↓停 3 秒↓继续 Render
所以:
Client:
xxxxxxxxxxRender↓Commit↓useEffect↓fetch
Server:
xxxxxxxxxxawait fetch↓Render↓HTML
这是最大的区别。
这是 React 19 面试很喜欢问的。
例如:
xxxxxxxxxxconst users = use(fetch("/api/users"));看起来:
没有 useEffect 了。
其实:
React 并不是直接等待。
而是:
xxxxxxxxxxRender↓throw Promise↓Suspense 接管↓Promise resolve↓重新 Render
所以:
Client 仍然遵守:
xxxxxxxxxxRender 不做副作用
只是:
React 用 Suspense 帮你管理了异步。
Server Component 不需要使用
useEffect获取数据,因为它是在服务器执行的。服务器可以在渲染 JSX 之前直接await数据请求,等数据准备好后再生成 HTML 返回给浏览器,因此首屏就已经包含完整的数据。相比之下,useEffect是 Client Component 中用于处理副作用的 Hook,它只能在组件完成 Commit 后执行,因此客户端通常会经历"先渲染,再请求,再重新渲染"的过程。
Server Components don't need
useEffectfor data fetching because they run on the server. They canawaitdata before rendering the JSX, so the HTML sent to the browser already contains the required data. In contrast,useEffectonly runs after the component has been committed to the DOM, which means Client Components usually render first, fetch data afterward, and then re-render with the fetched data.
很多人会说:
"Server Component 可以直接在 Render 中请求数据。"
更准确的说法应该是:
Server Component 可以在渲染过程中等待异步数据(
await fetch),因为整个渲染发生在服务器环境,不会阻塞浏览器 UI,也不会产生客户端渲染阶段的副作用问题。客户端组件则不同,它们的 Render 必须保持纯且可中断,因此数据获取通常放在useEffect(或通过 Suspense/use 等机制交给 React 管理)。
这里的关键不是"能不能请求数据",而是执行环境不同:服务器可以等待数据后再输出 HTML,而浏览器需要尽快完成渲染,把耗时的异步工作放到渲染之后或交给 Suspense 机制处理。
很多人会直接回答:
- useState
- props
- context
其实这是 React 的答案,不是 Next.js 的答案。
在 Next.js 16 中,由于引入了 Server Components、Server Actions、Router Cache、use cache、Cache Components,组件重新渲染(re-render)的来源比传统 React 多了很多。
Next.js 16 中能够触发组件重新渲染(Re-render)的方式可以分成两类:
这些和 React 一致。
| 触发方式 | 是否 Re-render | 说明 |
|---|---|---|
useState | ✅ | 最常见 |
useReducer | ✅ | 更新 state |
| Props 改变 | ✅ | 父组件重新传递新的 props |
| Context Value 改变 | ✅ | 所有消费 Context 的组件 |
| 外部 Store(Redux、Zustand 等)更新 | ✅ | 订阅状态发生变化 |
| 父组件重新 Render | ✅ | 默认子组件也会重新 Render(除非 memo) |
例如:
xxxxxxxxxxconst [count, setCount] = useState(0);setCount(count + 1);↓
组件重新 Render。
这一部分就是 Next.js 面试真正想听的。
例如:
xxxxxxxxxx?page=1↓?page=2
如果:
xxxxxxxxxxexport default async function Page({ searchParams,}) {}那么searchParams 变化以后:
xxxxxxxxxxServer Component↓重新执行↓重新获取数据↓返回新的 RSC Payload
例如:
xxxxxxxxxxconst page = Number(searchParams.page);const users = await getUsers(page);页码变化:
↓
重新请求服务器。
例如:
xxxxxxxxxx/users/1↓/users/2export default async function Page({params,}) {}
params变化:
↓
整个 Page Server Component:
重新执行。
router.push()例如:
xxxxxxxxxxrouter.push("/dashboard");发生:
xxxxxxxxxxNavigation↓请求新的 RSC Payload↓Render
router.replace()一样:
xxxxxxxxxxrouter.replace()↓Navigation↓Server Component↓重新 Render
router.refresh()这是 Next.js 高频面试题。
xxxxxxxxxxrouter.refresh();作用:
xxxxxxxxxx重新请求当前 Route↓Server Components重新执行↓Client State 保留↓UI 更新
注意它不是:
xxxxxxxxxxwindow.location.reload()
不会:
只刷新:
xxxxxxxxxxServer Component Tree
例如:
xxxxxxxxxx"use server";export async function createUser() { }如果调用:
xxxxxxxxxxawait createUser();通常会:
xxxxxxxxxxrevalidateTag("users");或者:
xxxxxxxxxxrevalidatePath("/users");下一次:
xxxxxxxxxxServer Component↓重新获取数据↓Render
例如:
xxxxxxxxxx"use cache";cacheTag("users");然后:
xxxxxxxxxxrevalidateTag("users");或者:
xxxxxxxxxxupdateTag("users");缓存失效。
下一次 Server Component 重新执行。
例如登录:
xxxxxxxxxxcookies().set()或者注销:
xxxxxxxxxxcookies().delete()如果Server Component读取:
xxxxxxxxxxconst cookieStore = await cookies();Cookie变化:
↓
下一次请求 Server Component 重新执行。
例如:
xxxxxxxxxxheaders()如果请求 Header 不同。Server Component也会重新计算。
例如:
xxxxxxxxxxAccept-Language↓不同语言
↓
重新 Render。
例如:
xxxxxxxxxxconst user = await db.user.findUnique()如果缓存:失效。
再次请求:
↓
数据变化。
↓
Server Component重新 Render。
Client:
例如:
xxxxxxxxxx<Suspense fallback={}>Promise:
Resolve:
↓
重新 Render。
Server:
Streaming:
xxxxxxxxxxHeader↓Skeleton↓Chunk↓Chunk↓Chunk
每个Chunk都会更新 UI。
严格来说不是整个组件重新 Render。
而是:逐步完成组件树。
xxxxxxxxxxref.current = 100;不会。
原因:React 不追踪:
xxxxxxxxxxref.current
xxxxxxxxxxlocalStorage.setItem()不会。
React不知道localStorage变化。
xxxxxxxxxxlet count = 0;count++;不会。
xxxxxxxxxxstate.user.name = "Tom";不会。
因为没有:
xxxxxxxxxxsetState()
在 Next.js 16 中,组件重新渲染既可能来自 React,也可能来自 Next.js 自身。对于 Client Components,
useState、useReducer、Props、Context 和外部状态管理都会触发重新渲染。而对于 Server Components,导航(如router.push、router.refresh)、动态路由参数、Search Params、Server Actions 导致的数据更新、缓存失效(如revalidateTag、revalidatePath)以及请求相关信息(如 Cookie 和 Header)变化,都可能导致 Server Components 重新执行并生成新的 RSC Payload,从而更新页面。
In Next.js 16, re-renders can be triggered by both React and Next.js. On the client side, state updates (
useState,useReducer), prop changes, context updates, and external stores all cause Client Components to re-render. On the server side, navigation (router.push,router.refresh), route parameter changes, search parameter changes, Server Actions with cache invalidation, and changes to request-specific data like cookies or headers can cause Server Components to re-execute and send a new React Server Component payload to the client.
很多候选人会说:
"Server Component re-renders."
更准确的表达应该是:
Server Components don't re-render in the browser. They are re-executed on the server to generate a new React Server Component (RSC) payload, and the client merges that payload into the existing UI.
这是 React Server Components 的工作机制,也是 Next.js 16 面试中比较容易体现深度的一点。
是否理解 App Router 的设计目标。
App Router is the new routing system introduced in Next.js. It supports nested layouts, React Server Components, streaming, and better data-fetching patterns. It was designed to simplify complex application structures and improve performance.
老项目迁移。
xxxxxxxxxxPages Router↓Client-firstApp Router↓Server-first必问。
A React Server Component is rendered on the server and never shipped to the browser. It can access databases, APIs, and server resources directly, reducing client-side JavaScript and improving performance.
Server Components:
xxxxxxxxxxNo BrowserNo LifecycleNo Interactivity很多人答不清。
The "use client" directive marks a component as a Client Component, allowing the use of hooks, event handlers, and browser APIs.
是否知道:
xxxxxxxxxxasync function Page() { const posts = await getPosts();}直接获取。
不需要:
xxxxxxxxxxuseEffectStreaming SSR allows parts of a page to be sent to the browser as soon as they are ready, instead of waiting for the entire page to finish rendering.
是否理解:
xxxxxxxxxx<Suspense fallback={<Loading />}>与 Streaming 配合。
xxxxxxxxxxLoading StatesWaterfallsUser ExperienceServer Actions allow client components to invoke server-side functions directly without creating traditional API routes.
减少:
xxxxxxxxxxfetchREST layerboilerplate知道:
xxxxxxxxxx"use server"答案:
xxxxxxxxxxYes因为运行在服务器。
回答:
是否知道:
xxxxxxxxxx"use cache"例如:
xxxxxxxxxxasync function getPosts() { "use cache";}因为 Next16 正在弱化 ISR 心智模型。
关键词:
xxxxxxxxxxPredictabilityTransparencyControl实时数据:
xxxxxxxxxxStock PricesChat MessagesLive Data必须会。
是否理解:
xxxxxxxxxxStatic Shell+Dynamic Islands因为核心就是:
xxxxxxxxxx<Suspense>划分静态和动态边界。
是否会:
xxxxxxxxxxLayoutParallel RoutesServer ComponentsStreaming例如:
xxxxxxxxxxDate.now()Math.random()window从:
xxxxxxxxxxRequest↓RSC Render↓Streaming↓HTML↓Hydration↓Interactivity完整讲一遍。
如果时间有限,优先准备:
"use cache" do and why was it introduced?如果这 30 题你都能流畅回答,中高级 Next.js 岗位的大部分框架层面问题基本都能覆盖。
React Server Component 是运行在服务器上的组件。它会在服务器完成渲染,然后把结果发送给客户端,本身不会被打包到浏览器中。
它最大的优势是可以直接访问数据库、文件系统或者后端服务,同时减少发送给浏览器的 JavaScript 代码,提高性能。
A React Server Component is a component that runs on the server. It is rendered on the server and its code is not shipped to the browser.
The main benefit is that it can access databases and backend resources directly while reducing the amount of JavaScript sent to the client, which improves performance.
App Router 的目标是支持 React Server Components、Streaming 和嵌套路由等现代 React 能力。
相比 Pages Router,它提供了更好的布局复用、更灵活的数据获取方式,以及更好的性能优化能力。
The App Router was introduced to support modern React features such as Server Components, Streaming, and nested layouts.
Compared with the Pages Router, it provides better layout reuse, more flexible data fetching, and improved performance.
Server Component 默认运行在服务器上,可以直接获取数据,但不能使用 useState、useEffect 或浏览器 API。
Client Component 运行在浏览器中,可以处理用户交互、状态管理和生命周期,但会增加客户端 JavaScript 的体积。
一般来说,静态内容放在 Server Component,交互逻辑放在 Client Component。
Server Components run on the server and can fetch data directly, but they cannot use hooks like useState or useEffect.
Client Components run in the browser and support interactivity, state management, and browser APIs, but they increase the JavaScript bundle size.
A common practice is to keep static content on the server and interactive logic on the client.
"use client" 是一个指令,用来告诉 Next.js 这个组件需要在浏览器运行。
只有标记为 Client Component 后,才能使用 useState、useEffect、事件处理函数以及浏览器 API。
The "use client" directive tells Next.js that a component should run on the client.
Once a component is marked as a Client Component, it can use hooks, event handlers, and browser APIs.
Server Actions 是 Next.js 提供的一种调用服务器逻辑的方式。
客户端组件可以直接调用服务器函数,而不需要手动创建 API Route。
这样可以减少样板代码,让前后端交互更加简单。
Server Actions allow Client Components to call server-side functions directly without creating traditional API routes.
They reduce boilerplate code and simplify communication between the client and the server.
API Route 需要定义接口、发送请求、解析响应。
而 Server Action 可以直接调用服务器函数,代码更少,类型推导更好,开发体验也更好。
不过对于开放给第三方使用的接口,API Route 仍然是更合适的选择。
With API Routes, you need to define endpoints, send requests, and handle responses manually.
Server Actions allow direct invocation of server functions, resulting in less code and better type safety.
However, API Routes are still useful for public APIs and third-party integrations.
Suspense 是 React 提供的异步加载机制。
当组件等待数据时,可以先显示 fallback 内容,等数据准备好之后再显示真正的 UI。
它让加载状态管理更加统一,也能和 Streaming 一起工作。
Suspense is a React feature for handling asynchronous rendering.
While data is loading, React can show a fallback UI and then render the actual content once the data is ready.
It simplifies loading states and works closely with Streaming.
Streaming SSR 允许服务器分批把页面内容发送给浏览器,而不是等整个页面渲染完成再一次性返回。
这样用户可以更早看到页面内容,提高首屏体验。
Streaming SSR allows the server to send parts of a page to the browser as soon as they are ready instead of waiting for the entire page to finish rendering.
This improves perceived performance and reduces the time to first meaningful content.
PPR 是 Next.js 16 重点推广的渲染模式。
它会先预渲染页面的静态部分,然后通过 Streaming 动态加载需要实时数据的部分。
简单来说,它结合了静态渲染和动态渲染的优点。
Partial Prerendering, or PPR, is a rendering strategy that combines static and dynamic rendering.
The static shell is prerendered ahead of time, while dynamic sections are streamed later when their data becomes available.
"use cache" 是 Next.js 16 引入的显式缓存机制。
开发者可以明确告诉 Next.js 哪些数据应该缓存,而不是依赖框架的隐式缓存规则。
这样缓存行为更加可预测,也更容易维护。
"use cache" is an explicit caching mechanism introduced in Next.js 16.
It allows developers to clearly define which data should be cached instead of relying on implicit framework behavior.
This makes caching more predictable and easier to understand.
因为 Server Component 运行在服务器上,它只负责生成 UI 结果,不会在浏览器中持续存在。
而 useState 和 useEffect 都依赖组件在客户端的生命周期。服务器渲染完成后组件就销毁了,所以没有状态更新和副作用执行的概念。
因此 React 不允许在 Server Component 中使用这些 Hooks。
Server Components run only on the server and do not stay alive after rendering.
Hooks like useState and useEffect depend on a component lifecycle in the browser. Since Server Components are rendered once and then discarded, there is no lifecycle or state updates to manage.
That's why React does not allow these hooks in Server Components.
RSC Payload 可以理解为 React Server Components 的渲染结果。
服务器不会直接把整个组件代码发送给浏览器,而是生成一种特殊的数据格式,描述组件树和需要渲染的内容。
客户端 React 再根据这个 Payload 组装最终的 UI。
这样可以减少发送到浏览器的 JavaScript 数量。
The RSC Payload is a special data format generated by React Server Components.
Instead of sending component code to the browser, the server sends a serialized representation of the component tree and its rendered output.
The client React runtime uses this payload to reconstruct the UI while keeping the JavaScript bundle smaller.
首先浏览器发起请求。
Next.js 会在服务器执行 Server Components,获取数据并生成 RSC Payload。
然后服务器把 HTML 和 RSC Payload 流式发送给浏览器。
浏览器先显示静态内容,随后下载 Client Components 的 JavaScript。
最后 React 完成 Hydration,让页面变成可交互状态。
The browser sends a request to the server.
Next.js renders Server Components, fetches data, and generates the RSC Payload.
The server then streams HTML and the RSC Payload to the browser.
The browser displays the initial content, downloads the Client Component JavaScript, and finally React hydrates the page to make it interactive.
Hydration Mismatch 是指服务器生成的 HTML 和客户端首次渲染结果不一致。
常见原因包括:
因为两边渲染结果不同,React 就会报 Hydration Error。
A hydration mismatch happens when the HTML generated on the server is different from the HTML produced by the client during hydration.
Common causes include Date.now(), Math.random(), inconsistent data, and browser-only APIs such as window or localStorage.
When the output differs, React reports a hydration error.
当组件读取的数据还没有准备好时,它会抛出一个 Promise。
React 捕获这个 Promise 后,会暂停当前组件的渲染,并显示 Suspense 的 fallback。
当 Promise 完成后,React 会重新尝试渲染这个组件。
所以 Suspense 本质上是一种基于 Promise 的渲染协调机制。
When a component tries to read data that is not ready, it throws a Promise.
React catches that Promise, pauses rendering for that component, and shows the Suspense fallback.
Once the Promise resolves, React retries the render and displays the actual content.
In essence, Suspense is a Promise-based rendering coordination mechanism.
PPR 会先生成一个静态页面外壳,例如 Header、Sidebar 和导航栏。
动态区域会被 Suspense 边界包裹。
用户访问页面时,静态部分立即返回,而动态部分通过 Streaming 在数据准备好后逐步发送。
这样既保留了静态页面的速度,也支持动态内容。
PPR first generates a static shell containing content such as headers, navigation, and layouts.
Dynamic sections are wrapped in Suspense boundaries.
The static shell is delivered immediately, while dynamic content is streamed later as the data becomes available.
This combines the benefits of static rendering and dynamic rendering.
在 App Router 中,组件默认都是 Server Components。
只有添加了 "use client" 的组件才会被打包到浏览器。
所以 Next.js 的原则是 Server First,只有真正需要交互的时候才使用 Client Component。
In the App Router, components are Server Components by default.
Only components marked with "use client" are bundled and executed in the browser.
The overall approach is server-first, using Client Components only when interactivity is required.
最有效的方法是尽可能使用 Server Components。
另外可以减少 use client 的使用范围、使用动态导入、按需加载第三方库,以及避免把大型工具函数放到客户端。
核心原则就是尽量减少发送到浏览器的 JavaScript。
The most effective approach is to use Server Components whenever possible.
Other techniques include minimizing the use of "use client", using dynamic imports, lazy-loading libraries, and keeping heavy logic on the server.
The goal is to reduce the amount of JavaScript sent to the browser.
我会使用 Layout 来共享导航和侧边栏。
数据展示区域优先使用 Server Components 获取数据。
对于图表、筛选器和表单等交互部分,我会使用 Client Components。
同时结合 Suspense 和 Streaming,让不同模块独立加载,避免整个页面被慢接口阻塞。
I would use layouts to share common UI such as navigation and sidebars.
Data-heavy sections would be implemented as Server Components, while interactive features like charts, filters, and forms would be Client Components.
I would also use Suspense and Streaming so that each section can load independently without blocking the entire page.
我认为最大的优势是 Server Components。
因为很多逻辑和数据获取可以直接在服务器完成,不需要把相关 JavaScript 发送到浏览器。
这样不仅减少 Bundle Size,也能改善首屏性能和用户体验。
I believe the biggest advantage is React Server Components.
They allow data fetching and rendering to happen on the server, reducing the amount of JavaScript sent to the browser.
This leads to smaller bundles, faster initial loads, and a better user experience.
React Flight 是 React Server Components 使用的一种传输协议。
它的作用不是传输 HTML,而是传输组件树的信息。
服务器会把组件结构、Props 和组件引用序列化成 Flight Payload,然后发送给客户端。
客户端 React 根据这些数据重建最终的组件树。
简单来说,Flight 是 Server Components 和客户端之间的通信协议。
React Flight is the transport protocol used by React Server Components.
Instead of sending HTML, it sends a serialized representation of the component tree, props, and component references.
The client React runtime consumes this payload and reconstructs the UI.
In simple terms, Flight is the communication protocol between Server Components and the browser.
因为 Server Component 的代码不会发送到浏览器。
例如数据库查询、数据转换或者权限判断等逻辑,都只运行在服务器。
客户端只接收最终结果,而不是接收这些代码。
所以随着 Server Component 使用得越多,浏览器需要下载的 JavaScript 就越少。
Server Components reduce bundle size because their code never gets shipped to the browser.
Operations such as database queries, data transformation, and authorization checks run entirely on the server.
The browser receives only the rendered result instead of the implementation code.
As more logic moves into Server Components, the client bundle becomes smaller.
不一定。
是否重新渲染取决于缓存策略。
如果使用 Cache Components 或者静态优化,Next.js 可能直接复用缓存结果。
如果是动态数据或者禁用了缓存,才会在每次请求时重新执行。
所以 Server Component 不等于 SSR。
Not necessarily.
Whether a Server Component runs again depends on the caching strategy.
With caching enabled, Next.js may reuse previously generated results.
Only dynamic or uncached components are rendered again on each request.
So a Server Component is not the same thing as SSR.
不是。
SSR 是一种渲染方式。
Server Component 是一种组件模型。
SSR 关注的是页面在哪里渲染。
Server Component 关注的是组件代码是否发送到浏览器。
两者可以一起使用,但解决的问题完全不同。
No.
SSR is a rendering strategy, while Server Components are a component model.
SSR focuses on where rendering happens.
Server Components focus on whether component code is shipped to the browser.
They often work together, but they solve different problems.
从开发者视角看,像是在直接调用服务器函数。
但底层实际上还是通过 HTTP 请求完成的。
Next.js 会为 Server Action 生成唯一标识。
客户端触发 Action 时,会发送请求到服务器。
服务器执行对应函数,然后把结果返回给 React。
所以它本质上是一种 RPC 风格的调用方式。
Although Server Actions feel like direct function calls, they are implemented through HTTP requests.
Next.js generates an identifier for each action.
When the client invokes an action, a request is sent to the server, which executes the function and returns the result.
Conceptually, it behaves like an RPC mechanism.
主要是开发体验更好。
以前需要:
现在直接调用服务器函数即可。
同时 TypeScript 类型可以自动推导。
不过对于开放 API 或第三方集成场景,传统 API 依然更合适。
The main advantage is developer experience.
Traditionally, developers had to create API routes, write fetch requests, handle JSON serialization, and maintain types.
Server Actions remove much of that boilerplate and provide better TypeScript integration.
Public APIs and third-party integrations still benefit from traditional API endpoints.
因为以前 Next.js 的缓存规则过于隐式。
很多开发者搞不清楚数据什么时候会缓存,什么时候会重新验证。
"use cache" 把缓存变成显式声明。
看到代码就能知道这个函数会被缓存。
这样可预测性和可维护性都更好。
Caching behavior in earlier versions of Next.js was often implicit and difficult to reason about.
Developers were not always sure when data would be cached or revalidated.
"use cache" makes caching explicit, improving predictability and maintainability.
PPR 解决的是静态渲染和动态渲染之间的矛盾。
以前:
要么全静态。
要么全动态。
PPR 可以把页面拆开。
静态部分提前生成。
动态部分按需流式加载。
这样既保证性能,又支持实时数据。
PPR solves the trade-off between static rendering and dynamic rendering.
Previously, pages were often either fully static or fully dynamic.
PPR allows a static shell to be prerendered while dynamic sections are streamed later.
This provides both performance and flexibility.
因为 React 需要知道哪些区域可以先显示,哪些区域需要等待数据。
Suspense 就是这个边界。
当数据未准备好时,React 可以先渲染 fallback。
数据准备好后再替换成真实内容。
Streaming 和 PPR 都依赖这种机制来实现分阶段渲染。
React needs a way to identify which parts of the UI are ready and which parts must wait for data.
Suspense provides that boundary.
It allows React to show fallback content first and replace it later when the data is available.
Both Streaming and PPR rely heavily on Suspense boundaries.
我会选择 React Server Components。
因为它不仅能减少客户端 JavaScript,还能把数据获取和渲染放到服务器完成。
很多性能优化,例如更小的 Bundle、更快的首屏和更好的 SEO,本质上都受益于 Server Components。
I would choose React Server Components.
They reduce client-side JavaScript and allow data fetching and rendering to happen on the server.
Many performance benefits, such as smaller bundles, faster initial loads, and improved SEO, ultimately come from Server Components.
有,而且 Next.js 16 现在已经逐渐开始进入面试题库了。
不过面试官一般不会问:
"Next.js 16 发布了什么新特性?"
而是会问:
"Next.js 16 为什么要引入这些变化?解决了什么问题?"
这才是考察重点。
在 Next.js 15 以及之前,缓存规则比较隐式。
开发者经常搞不清楚:
Next.js 16 引入 "use cache",把缓存变成显式声明。
看到代码就能知道哪些逻辑会被缓存,从而提高可预测性和可维护性。
Before Next.js 16, caching behavior was often implicit and difficult to reason about.
Developers were not always sure when data would be cached or revalidated.
The "use cache" directive makes caching explicit, improving predictability and maintainability.
Cache Components 允许以组件为单位进行缓存。
以前缓存更多是页面级别或者请求级别。
现在可以缓存页面中的某个组件,而其他部分保持动态。
这样缓存粒度更细,性能优化更加灵活。
Cache Components allow caching at the component level.
Previously, caching was often applied at the page or request level.
With Cache Components, individual sections of a page can be cached while others remain dynamic.
This provides more granular performance optimization.
React Server Components 决定组件运行在服务器。
Cache Components 决定服务器执行结果是否缓存。
一个关注执行位置。
一个关注执行结果。
两者经常一起使用。
React Server Components determine where components run.
Cache Components determine whether the rendered result should be cached.
One focuses on execution location, while the other focuses on caching behavior.
隐式缓存虽然简单,但随着项目变大很难维护。
开发者经常不知道某个数据为什么缓存或者为什么失效。
显式缓存把缓存策略写在代码里。
阅读代码时就能理解缓存行为。
这对于大型团队特别重要。
Implicit caching is convenient at first but becomes difficult to maintain in large applications.
Developers often struggle to understand why data is cached or invalidated.
Explicit caching makes the behavior visible in code, improving readability and maintainability.
Next.js 16 进一步把 PPR 和 Cache Components 结合起来。
开发者可以更容易地定义:
从而实现更细粒度的页面拆分。
Next.js 16 integrates PPR more closely with Cache Components.
Developers can more clearly define which parts of a page are static and which are dynamic.
This enables more granular rendering strategies.
因为现实中的页面通常既有静态内容,也有动态内容。
传统方案只能:
PPR 可以同时支持两者。
既保证首屏速度,又支持实时数据。
Most real-world pages contain both static and dynamic content.
Traditional approaches often force developers to choose between fully static and fully dynamic rendering.
PPR combines both, providing fast initial loads and dynamic updates.
很多开发者误以为 Middleware 运行在应用内部。
实际上它更接近网络代理层。
改名为 proxy.ts 是为了让职责更清晰。
让开发者意识到它属于请求进入应用之前的处理阶段。
Many developers assumed Middleware was part of the application layer.
In reality, it behaves more like a request proxy.
Renaming it to proxy.ts makes its purpose clearer and better reflects where it operates in the request lifecycle.
Turbopack 使用 Rust 编写。
相比 Webpack,它在大型项目中的启动速度和增量编译速度更快。
对于开发体验提升非常明显。
尤其是大型 Monorepo 项目。
Turbopack is written in Rust and offers significantly faster startup and incremental build performance compared to Webpack.
The biggest benefit is improved developer experience, especially in large codebases.
主要有三个原因:
因此修改一个文件时,只需要重新计算受影响部分。
Turbopack is faster because of Rust's performance, aggressive incremental computation, and fine-grained dependency tracking.
When a file changes, only the affected parts need to be recomputed.
我认为是从“隐式优化”转向“显式优化”。
以前很多缓存和渲染行为由框架自动决定。
Next.js 16 开始让开发者主动声明:
这样系统行为更加可预测。
对于大型项目非常重要。
I believe the most important architectural shift is moving from implicit optimization to explicit optimization.
Instead of the framework making hidden decisions, developers now explicitly define caching and rendering behavior.
This improves predictability and scalability for large applications.
如果时间有限,只背这 5 个:
use cache solve?如果这 5 题能用英文流畅回答,面试官基本能判断:
你不是只会用 Next.js 14/15,而是跟上了 Next.js 16 的架构演进方向。